﻿using System.Collections.Generic;
using UnityEditor;
using UnityEngine;
using System.IO;

namespace TinyAsset.Editor
{
    public class BuildCollectTask : IBuildTask
    {
        Dictionary<string, string> AssetNameToBundleName = new Dictionary<string, string>();

        Dictionary<string, FileCollectionRule> BundleNameToRule = new Dictionary<string, FileCollectionRule>();

        BuildSetting buildSetting;

        public bool Execute(BuildContext context)
        {
            buildSetting = context.buildSetting;

            Dictionary<string, List<string>> bundles = new Dictionary<string, List<string>>();
            Dictionary<string, string> nativeAssets = new Dictionary<string, string>();

            foreach (var item in buildSetting.collectionSetting.assetBundles)
            {
                var results = item.Collect();
                foreach (var collectionAssetResult in results)
                {
                    string assetBundleName = collectionAssetResult.GetAssetBundleName(".ab");
                    List<string> list;
                    if (!bundles.TryGetValue(assetBundleName, out list))
                    {
                        list = new List<string>();
                        bundles.Add(assetBundleName, list);
                    }
                    list.Add("Assets/" + collectionAssetResult.assetPath);

                    if (!BundleNameToRule.ContainsKey(assetBundleName))
                        BundleNameToRule.Add(assetBundleName, collectionAssetResult.fileCollectionRule);
                }
            }

            foreach (var item in buildSetting.collectionSetting.raws)
            {
                var results = item.Collect();
                foreach (var collectionAssetResult in results)
                    nativeAssets.Add("Assets/" + collectionAssetResult.assetPath, collectionAssetResult.fileCollectionRule.tag);
            }

            foreach (var item in bundles)
            {
                item.Value.ForEach((assetName) => {
                    AssetNameToBundleName.Add(assetName, item.Key);
                });
            }

            context.nativeAssets = nativeAssets;
            context.assetBundles = Create(bundles);

            return true;
        }

        Dictionary<string, AssetBundleBuildNode> Create(Dictionary<string, List<string>> bundles)
        {
            Dictionary<string, AssetBundleBuildNode> map = new Dictionary<string, AssetBundleBuildNode>();

            foreach (var item in bundles)
            {
                AssetBundleBuildNode node = new AssetBundleBuildNode()
                {
                    AssetBundleName = item.Key,
                    TagName = BundleNameToRule[item.Key].tag,
                };
                node.Assets.AddRange(item.Value);
                map.Add(node.AssetBundleName, node);
            }

            map.Add(AssetBundleUtility.kSharedAssetBundle, new AssetBundleBuildNode()
            {
                TagName = AssetBundleUtility.kBuildin,
                AssetBundleName = AssetBundleUtility.kSharedAssetBundle,
            });

            foreach (var item in bundles)
            {
                string[] dependencies = AssetDatabase.GetDependencies(item.Value.ToArray(), false);
                AssetBundleBuildNode node = map[item.Key];
                foreach (var dependency in dependencies)
                {
                    string ext = Path.GetExtension(dependency).ToLower();
                    if (ext == ".cs")
                        continue;

                    if (AssetNameToBundleName.TryGetValue(dependency, out string bundleName))
                    {
                        AssetBundleBuildNode t = map[bundleName];
                        if (t.AssetBundleName != node.AssetBundleName)
                        {
                            if (!node.Children.ContainsKey(bundleName))
                                node.Children.Add(bundleName, t);

                            if (!t.Parent.ContainsKey(node.AssetBundleName))
                                t.Parent.Add(node.AssetBundleName, node);
                        }
                    }
                    else
                        node.Individual.Add(dependency);
                }
            }
            return map;
        }
    }
}